#include "stdafx.h"
#include "Breakpoint.h"

LUA_DEBUG_BEGIN

Breakpoint::Breakpoint(const std::string &key, int line,
                       bool isInternal, bool isTemp)
                       : m_key(key), m_line(line)
                       , m_isInternal(isInternal), m_isTemp(isTemp) {
}

Breakpoint::~Breakpoint() {
}


BreakpointList::BreakpointList(RemoteEngine_ptr engine)
: m_engine(engine)
{
    assert(engine != NULL);
}

BreakpointList::~BreakpointList()
{
}

Breakpoint BreakpointList::Find(const std::string &key, int line)
{
    Breakpoint bp(key, line);

    ImplSet::const_iterator it = m_set.find(bp);
    if (it == m_set.end()) {
        return Breakpoint();
    }

    return *it;
}

Breakpoint BreakpointList::First(const std::string &key)
{
    // Find the breakpoint which has the least line number.
    Breakpoint tmp(key, -1);
    ImplSet::const_iterator it = m_set.lower_bound(tmp);
    if (it == m_set.end()) {
        return Breakpoint();
    }

    // Check whether the keys are same.
    if (it->GetKey() != key) {
        return Breakpoint();
    }

    return *it;
}

Breakpoint BreakpointList::Next(const Breakpoint &bp) 
{
    // Increment line number and find next.
    Breakpoint tmp(bp.GetKey(), bp.GetLine() + 1);
    ImplSet::const_iterator it = m_set.lower_bound(tmp);
    if (it == m_set.end()) {
        return Breakpoint();
    }

    // Check whether the keys are same.
    if (it->GetKey() != bp.GetKey()) {
        return Breakpoint();
    }

    return *it;
}

void BreakpointList::Set(const Breakpoint &bp)
{
    if (!bp.IsOk()) {
        return;
    }

    // Insert certainly.
    ImplSet::iterator it = m_set.find(bp);
    if (it != m_set.end()) {
        m_set.erase(it);
    }
    m_set.insert(bp);

    RemoteEngine_ptr pengine = m_engine.lock();
    if (pengine != NULL) {
        if( pengine->type() == pengine->CLIENT_SIDE )
            pengine->SendSetBreakpoint(bp);
        else
            pengine->SendChangedBreakpointList(*this);
    }
}

void BreakpointList::Remove(const Breakpoint &bp) {
    if (!bp.IsOk()) {
        return;
    }

    ImplSet::iterator it = m_set.find(bp);
    if (it == m_set.end()) {
        return;
    }
    m_set.erase(it);

    RemoteEngine_ptr pengine = m_engine.lock();
    if (pengine != NULL) {
        if( pengine->type() == pengine->CLIENT_SIDE )
            pengine->SendRemoveBreakpoint(bp);
        else
            pengine->SendChangedBreakpointList(*this);
    }
}

void BreakpointList::Toggle(const std::string &key, int line) {
    Breakpoint bp(key, line);

    // erase if it exists, add if it isn't
    ImplSet::iterator it = m_set.find(bp);
    if (it == m_set.end()) {
        Set(bp);
    }
    else {
        Remove(bp);
    }
}

LUA_DEBUG_END
